package com.haifeng.sbtx.common.util;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
import java.util.Set;

/**
 * <p>
 *  RestTemplate工具类
 * </p>
 *
 * @author: Haifeng
 * @date: 2019-12-02
 */
@Slf4j
@Component
@AllArgsConstructor
public class RestTemplateUtils {

    private final RestTemplate restTemplate;

    /**
     * http 请求 GET
     *
     * @param url 地址
     * @param map 参数
     * @return String
     */
    public String getHttp(String url, Map<String, Object> map) throws Exception{
        try {
            return restTemplate.getForObject(expandUrl(url,map),String.class,map);
        } catch (Exception e) {
            String msg = String.format("GET调用服务失败:url:%s,error:%s" , url,e.getMessage());
            log.error(msg);
            throw new Exception(msg,e.getCause());
        }
    }

    /**
     * http 请求 post(默认使用表单模式)
     *
     * @param url 地址
     * @param params 参数
     * @return String
     */
    public String postHttp(String url, Map<String, Object> params) throws Exception {
        return postHttp(url,params, MediaType.APPLICATION_FORM_URLENCODED);
    }

    /**
     * http 请求 post
     *
     * @param url 地址
     * @param params 参数
     * @return String
     */
    public String postHttp(String url, Map<String, Object> params, MediaType mediaType) throws Exception {
        MultiValueMap<String, String> map = getMap(params);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

        try {
            return restTemplate.postForObject(url, request, String.class);
        } catch (Exception e) {
            String msg = String.format("POST调用服务失败:url:%s,error:%s" , url,e.getMessage());
            log.error(msg);
            throw new Exception(msg,e.getCause());
        }
    }

    /**
     * PUT、DELETE（带返回值）(默认使用表单模式)
     * @param url
     * @param params
     * @param method
     * @return
     * @throws Exception
     */
    public String putOrDelete(String url,Map<String, Object> params, HttpMethod method) throws Exception{
        return putOrDelete(url,params,method, MediaType.APPLICATION_FORM_URLENCODED);
    }

    /**
     * PUT、DELETE（带返回值）
     * @param url
     * @param params
     * @param method
     * @return
     * @throws Exception
     */
    public String putOrDelete(String url, Map<String, Object> params, HttpMethod method, MediaType mediaType) throws Exception{
        MultiValueMap<String, String> map = getMap(params);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        try {
            // 发送请求
            ResponseEntity<String> resultEntity = restTemplate.exchange(url, method, request, String.class);
            return resultEntity.getBody();
        } catch (Exception e) {
            String msg = String.format("%s调用服务失败:url:%s,error:%s" ,method.name(), url,e.getMessage());
            log.error(msg);
            throw new Exception(msg,e.getCause());
        }
    }

    private MultiValueMap<String, String> getMap(Map<String,Object> params) {
        MultiValueMap<String, String> map= new LinkedMultiValueMap<>(20);
        if (params != null && !params.isEmpty()){
            for(Map.Entry<String, Object> entry : params.entrySet()){
                map.add(entry.getKey(),entry.getValue() != null ? String.valueOf(entry.getValue()) : "");
            }
        }
        return map;
    }


    private String expandUrl(String url, Map map) {
        StringBuilder sb = new StringBuilder(url);
        sb.append("?");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            sb.append(key).append("=").append(map.get(key)).append("&");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }
}
